package app.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedList;

import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;

public class FileUtilities extends FileFilter {
	private OutputStream out;
	private InputStream in;
	public JProgressBar progressBar;
	private boolean copyingFlag = false;

	/**
	 * @variale Example: {"txt", "log"}
	 */
	private ArrayList<String> acceptExtention = new ArrayList<>();

	public FileUtilities() {
	}

	public FileUtilities(String... acceptExtention) {
		this.addAcceptExtention(acceptExtention);
	}

	/**
	 * @param source
	 *            file for copying
	 * @param target
	 *            new copied file
	 * @return boolean TRUE if successfully copy
	 */
	public boolean copyFile(File source, File target) {
		copyingFlag = false;
		if(!source.exists()) {
			return false;
		}
		try {
			this.in = new FileInputStream(source);
			this.out = new FileOutputStream(target);

			// configure progress bar
			if(progressBar != null) {
				progressBar.setMaximum(in.available());
				progressBar.setMinimum(0);
			}

			Runnable threadCopying = new Runnable() {

				@Override
				public void run() {
					if(in == null || out == null) {
						System.err.println("Error in copying file. -- " + getClass().getName());
						return;
					}
					byte[] buffer = new byte[1024];
					int bytesRead;
					try {
						bytesRead = in.read(buffer);
						while (bytesRead >= 0) {
							out.write(buffer, 0, bytesRead);
							bytesRead = in.read(buffer);

							if(progressBar != null)
								progressBar.setValue(in.available());
						}
					}catch (IOException e) {
						e.printStackTrace();
					}finally {
						try {
							in.close();
							out.close();
						}catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			};
			SwingUtilities.invokeLater(threadCopying);
			// set copyingFlag = true
			copyingFlag = true;
		}catch (IOException e) {
			e.printStackTrace();
		}
		return copyingFlag;
	}

	@Override
	public boolean accept(File f) {
		return isAcceptable(f);
	}

	@Override
	public String getDescription() {
		return "Properties File";
	}

	public boolean isAcceptable(File f) {
		if(acceptExtention.isEmpty() || f == null) {
			return false;
		}

		if(f.isDirectory()) {
			return true;
		}
		else {
			String fileExtention = getExtension(f);
			for(String str : acceptExtention) {
				if(fileExtention != null && fileExtention.equalsIgnoreCase(str)) {
					return true;
				}
			}
		}

		return false;
	}

	public String getExtension(File f) {
		String str = f.getName();
		int index = str.lastIndexOf('.');

		if(index > 0 && index < str.length() - 1) {
			return str.substring(index + 1).toLowerCase();
		}

		return null;
	}

	public ArrayList<String> getAcceptExtention() {
		return acceptExtention;
	}

	/**
	 * @param acceptExtention
	 *            : Example String acceptExtention = "txt";
	 */
	public void addAcceptExtention(String... acceptExtention) {
		for(String str : acceptExtention)
			this.acceptExtention.add(str);
	}

	/**
	 * @param fileName
	 *            (String)
	 * @return File name without extension
	 */
	public String removeExtension(String fileName) {
		int n = fileName.lastIndexOf(".");
		if(n > 0 && n < fileName.length() - 1) {
			return fileName.substring(0, n);
		}
		return fileName;
	}

	/**
	 * Move a file from a folder to another folder
	 * 
	 * @param file
	 *            File being moved
	 * @param dir
	 *            Direction for moving to here
	 * @return true if successfully moving
	 */
	public boolean moveFile(File file, File dir) {
		if(!dir.isDirectory()) {
			return false;
		}

		if(file.getPath().contains(dir.getPath())) {
			return false;
		}

		File target = new File(dir.getPath() + "/" + file.getName());
		boolean flag = copyFile(file, target);
		if(flag)
			file.delete();
		return flag;
	}

	/**
	 * List all files in a directory
	 * 
	 * @param dir
	 * @param listOfNames
	 */
	public void listAllFiles(File dir, LinkedList<String> listOfNames) {
		if(dir == null || !dir.exists()) {
			return;
		}

		if(dir.isDirectory()) {
			File[] files = dir.listFiles();
			for(File f : files) {
				if(f.isFile()) {
					listOfNames.add(f.getName());
				}
				else if(f.isDirectory()) {
					listAllFiles(f, listOfNames);
				}
			}
		}
		else if(dir.isFile()) {
			listOfNames.add(dir.getName());
		}

		return;
	}
}
